package cn.anecansaitin.jep;

import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
import java.util.Map;

public enum TokenType {
    // 基本类型
    SHORT("short", -1),
    INT("int", -1),
    LONG("long", -1),
    FLOAT("float", -1),
    DOUBLE("double", -1),
    BYTE("byte", -1),
    CHAR("char", -1),
    BOOLEAN("boolean", -1),

    // 变量引用
    THIS("this", -1),
    SUPER("super", -1),
    VOID("void", -1),

    // 流程控制
    BREAK("break", -1),
    CASE("case", -1),
    CONTINUE("continue", -1),
    ELSE("else", -1),
    FOR("for", -1),
    IF("if", -1),
    INSTANCEOF("instanceof", -1),
    RETURN("return", -1),
    SWITCH("switch", -1),
    WHILE("while", -1),

    // 访问控制
    PUBLIC("public", -1),
    PROTECTED("protected", -1),
    PRIVATE("private", -1),
    DEFAULT("default", -1),

    // 修饰符
    ABSTRACT("abstract", -1),
    CLASS("class", -1),
    EXTENDS("extends", -1),
    FINAL("final", -1),
    IMPLEMENTS("implements", -1),
    INTERFACE("interface", -1),
    NEW("new", -1),
    STATIC("static", -1),

    // 基础值
    TRUE_LITERAL("true", -1),
    FALSE_LITERAL("false", -1),
    NULL("null", -1),

    // 赋值运算符 (优先级最低)
    ASSIGN("=", 1),
    ASSIGN_PLUS("+=", 1),
    ASSIGN_MINUS("-=", 1),
    ASSIGN_MULTIPLY("*=", 1),
    ASSIGN_DIVIDE("/=", 1),
    ASSIGN_MODULO("%=", 1),
    ASSIGN_BIT_LEFT("<<=", 1),
    ASSIGN_BIT_RIGHT(">>=", 1),
    ASSIGN_BIT_AND("&=", 1),
    ASSIGN_BIT_XOR("^=", 1),
    ASSIGN_BIT_OR("|=", 1),

    // 三元运算符
    QUESTION("?", 2),

    // 逻辑或
    OR("||", 3),

    // 逻辑与
    AND("&&", 4),

    // 位或
    BIT_OR("|", 5),

    // 位异或
    BIT_XOR("^", 6),

    // 位与
    BIT_AND("&", 7),

    // 相等比较
    EQUAL("==", 8),
    NOT_EQUAL("!=", 8),

    // 关系比较
    LESS_THAN("<", 9),
    GREATER_THAN(">", 9),
    LESS_THAN_EQUAL("<=", 9),
    GREATER_THAN_EQUAL(">=", 9),

    // 位移
    BIT_LEFT("<<", 10),
    BIT_RIGHT(">>", 10),
    BIT_RIGHT_UNSIGNED(">>>", 10),

    // 加减
    PLUS("+", 11),
    MINUS("-", 11),

    // 乘除模
    MULTIPLY("*", 12),
    DIVIDE("/", 12),
    MODULO("%", 12),

    // 幂运算
    POWER("**", 13),

    // 一元运算符
    BIT_NOT("~", 14),
    NOT("!", 14),
    UNARY_MINUS("-", 14),
    UNARY_PLUS("+", 14),
    INC("++", 14),
    DEC("--", 14),

    // 其他
    LEFT_PAREN("(", -1),
    RIGHT_PAREN(")", -1),
    LEFT_BRACKET("[", -1),
    RIGHT_BRACKET("]", -1),
    LEFT_BRACE("{", -1),
    RIGHT_BRACE("}", -1),
    DOT(".", -1),
    COMMA(",", -1),
    SEMICOLON(";", -1),
    COLON(":", -1),
    FUNCTION("function", -1),
    IDENTIFIER("identifier", -1),
    INT_LITERAL("int literal", -1),
    LONG_LITERAL("long literal", -1),
    FLOAT_LITERAL("float literal", -1),
    DOUBLE_LITERAL("double literal", -1),
    CHAR_LITERAL("char literal", -1),
    STRING_LITERAL("string literal", -1),
    EOF("eof", -1),
    ERROR("error", -1);

    public final String symbol;
    public final int precedence;

    TokenType(String symbol, int precedence) {
        this.symbol = symbol;
        this.precedence = precedence;
    }

    public boolean canBeUnary() {
        return switch (this) {
            case PLUS, MINUS, MULTIPLY, DIVIDE,
                 POWER, MODULO,
                 BIT_LEFT, BIT_RIGHT, BIT_RIGHT_UNSIGNED,
                 BIT_NOT, BIT_AND, BIT_OR, BIT_XOR,
                 ASSIGN,
                 LEFT_PAREN, COMMA, SEMICOLON -> true;
            default -> false;
        };
    }

    private static final Map<String, TokenType> KEY_WORDS;

    static {
        KEY_WORDS = new HashMap<>(33);
        KEY_WORDS.put("short", SHORT);
        KEY_WORDS.put("int", INT);
        KEY_WORDS.put("long", LONG);
        KEY_WORDS.put("float", FLOAT);
        KEY_WORDS.put("double", DOUBLE);
        KEY_WORDS.put("byte", BYTE);
        KEY_WORDS.put("char", CHAR);
        KEY_WORDS.put("boolean", BOOLEAN);
        KEY_WORDS.put("this", THIS);
        KEY_WORDS.put("super", SUPER);
        KEY_WORDS.put("void", VOID);
        KEY_WORDS.put("break", BREAK);
        KEY_WORDS.put("case", CASE);
        KEY_WORDS.put("continue", CONTINUE);
        KEY_WORDS.put("else", ELSE);
        KEY_WORDS.put("for", FOR);
        KEY_WORDS.put("if", IF);
        KEY_WORDS.put("instanceof", INSTANCEOF);
        KEY_WORDS.put("return", RETURN);
        KEY_WORDS.put("switch", SWITCH);
        KEY_WORDS.put("while", WHILE);
        KEY_WORDS.put("public", PUBLIC);
        KEY_WORDS.put("protected", PROTECTED);
        KEY_WORDS.put("private", PRIVATE);
        KEY_WORDS.put("default", DEFAULT);
        KEY_WORDS.put("abstract", ABSTRACT);
        KEY_WORDS.put("class", CLASS);
        KEY_WORDS.put("extends", EXTENDS);
        KEY_WORDS.put("final", FINAL);
        KEY_WORDS.put("implements", IMPLEMENTS);
        KEY_WORDS.put("interface", INTERFACE);
        KEY_WORDS.put("new", NEW);
        KEY_WORDS.put("static", STATIC);
    }

    public static TokenType getKeyword(String identifier) {
        return KEY_WORDS.get(identifier);
    }

    private static final Map<String, TokenType> LITERAL;

    static {
        LITERAL = new HashMap<>(3);
        LITERAL.put("true", TRUE_LITERAL);
        LITERAL.put("false", FALSE_LITERAL);
        LITERAL.put("null", NULL);
    }

    @Nullable
    public static TokenType getLiteral(String value) {
        return LITERAL.get(value);
    }

    @Override
    public String toString() {
        return name() + "[" + symbol + "]";
    }
}
